package com.chengyi.serialport.demo.adapter


import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import androidx.databinding.library.baseAdapters.BR
import androidx.recyclerview.widget.RecyclerView
import com.chengyi.serialport.demo.interfaces.IAdapterDataListener
import com.chengyi.serialport.demo.interfaces.OnDataChangedCallback
import io.reactivex.rxjava3.functions.Function
import me.goldze.mvvmhabit.binding.command.BindingAction
import me.goldze.mvvmhabit.binding.command.BindingCommand
import me.goldze.mvvmhabit.binding.command.BindingConsumer
import me.goldze.mvvmhabit.binding.viewadapter.view.ViewAdapter

/**
 * Created by Android on 2016/6/3.
 */
open class BindingAdapter<T : Any> @JvmOverloads constructor(
    private val mLayoutId: Int, private val mData: ArrayList<T> = ArrayList(), private val mOnDataChangedCallback: OnDataChangedCallback? = null,
    private val mViewModelVarId: Int = -1, private val mViewModel: Any? = null, private val mLayoutVarId: Int = BR.item
) : RecyclerView.Adapter<BindingAdapter<T>.DataBindingViewHolder>(), IAdapterDataListener {
    private var haveHeader = false
    private var haveFooter = false
    private var headerView: View? = null
    var onItemClickListener: BindingCommand<Int>? = null
    var onItemLongClickListener: BindingCommand<Int>? = null
    var footerView: View? = null
    var onBindingViewHolderListener: OnBindingViewHolderListener? = null
    val data: ArrayList<T> get() = mData

    init {
        if (getRealCount() < 1 && mOnDataChangedCallback?.isNoData != true) {
            mOnDataChangedCallback?.isNoData = true
            mOnDataChangedCallback?.onNoDataCallback()
        } else if (getRealCount() > 0 && mOnDataChangedCallback?.isNoData != false) {
            mOnDataChangedCallback?.isNoData = false
            mOnDataChangedCallback?.hideNoDataCallback()
        }
    }

    override var onDataChangedCallback: OnDataChangedCallback? = mOnDataChangedCallback

    constructor(
        layoutId: Int,
        layoutVarId: Int,
        data: ArrayList<T>,
        mOnDataChangedCallback: OnDataChangedCallback? = null
    ) : this(layoutId, data, mOnDataChangedCallback, -1, null, layoutVarId)

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DataBindingViewHolder {
        return when (viewType) {
            TYPE_HEADER -> DataBindingViewHolder(headerView!!, viewType)
            TYPE_FOOTER -> DataBindingViewHolder(footerView!!, viewType)
            else -> DataBindingViewHolder(LayoutInflater.from(parent.context).inflate(mLayoutId, parent, false), viewType)
        }
    }

    override fun onBindViewHolder(holder: DataBindingViewHolder, position: Int) {
        when (holder.viewType) {
            TYPE_HEADER -> {
            }

            TYPE_FOOTER -> {
            }

            else -> {
                val binding = DataBindingUtil.bind<ViewDataBinding>(holder.itemView)
                val position = if (haveHeader) position - 1 else position
                val data = mData[position]
                ViewAdapter.onClickCommand(holder.itemView, BindingCommand(BindingConsumer {
                    onItemClickListener?.execute(position)
                }))
                ViewAdapter.onLongClickCommand(holder.itemView, BindingAction {
                    onItemLongClickListener?.execute(position)
                })
                binding?.setVariable(mLayoutVarId, data)
                if (mViewModelVarId != -1 && mViewModel != null) {
                    binding?.setVariable(mViewModelVarId, mViewModel)
                }
                binding?.setVariable(BR.position, position)
                bindOther(holder, position, binding)
                binding?.executePendingBindings()
                onBindingViewHolderListener?.onHolderBinding(holder, position)
            }
        }
    }

    open fun bindOther(holder: DataBindingViewHolder, position: Int, binding: ViewDataBinding?) {

    }

    fun getItem(position: Int): T? {
        val realPosition = getRealPosition(position)
        return if (realPosition < getRealCount() && realPosition >= 0) {
            mData[realPosition]
        } else null
    }


    /**
     * 调用之后请调用NotifyDataSetChange 如果在setAdapter之后
     *
     * @param view
     */
    fun addFooterView(view: View) {
        haveFooter = true
        footerView = view
    }

    fun getRealCount(): Int {
        return mData.size
    }

    fun getRealPosition(position: Int): Int {
        return if (haveHeader) position - 1 else position
    }

    /**
     * 调用之后请调用NotifyDataSetChange 如果在setAdapter之后
     *
     * @param view
     */
    fun addHeaderView(view: View) {
        haveHeader = true
        headerView = view
    }

    fun removeFooterView() {
        footerView = null
        haveFooter = false
    }

    fun filter(filter: Function<T, Boolean>? = null): List<T> {
        return if (filter == null) {
            mData
        } else mData.filter {
            filter.apply(it)
        }
    }

    fun refresh(data: ArrayList<T>) {
        removeFooterView()
        mData.clear()
        mData.addAll(data)
        notifyDataSetChanged()
        if (getRealCount() < 1) {
            onDataChangedCallback?.isNoData = true
            onDataChangedCallback?.onNoDataCallback()
        } else if (getRealCount() > 0) {
            onDataChangedCallback?.isNoData = false
            onDataChangedCallback?.hideNoDataCallback()
        }
    }

    fun loadMore(data: ArrayList<T>) {
        mData.addAll(data)
        notifyDataSetChanged()
        if (getRealCount() < 1 && onDataChangedCallback?.isNoData != true) {
            onDataChangedCallback?.isNoData = true
            onDataChangedCallback?.onNoDataCallback()
        } else if (getRealCount() > 0 && onDataChangedCallback?.isNoData != false) {
            onDataChangedCallback?.isNoData = false
            onDataChangedCallback?.hideNoDataCallback()
        }
    }

    fun add(entity: T) {
        mData.add(entity)
        notifyDataSetChanged()
        if (onDataChangedCallback?.isNoData != false) {
            onDataChangedCallback?.isNoData = false
            onDataChangedCallback?.hideNoDataCallback()
        }
    }


    fun update(index: Int, entity: T) {
        mData.removeAt(index)
        mData.add(index, entity)
        notifyItemChanged(index)
    }

    fun delete(entity: T) {
        mData.remove(entity)
        notifyDataSetChanged()
        if (getRealCount() < 1) {
            onDataChangedCallback?.isNoData = true
            onDataChangedCallback?.onNoDataCallback()
        }
    }

    fun deleteAt(index: Int) {
        mData.removeAt(getRealPosition(index))
        notifyDataSetChanged()
        if (getRealCount() < 1) {
            onDataChangedCallback?.isNoData = true
            onDataChangedCallback?.onNoDataCallback()
        }
    }

    override fun getItemCount(): Int {
        var extraCount = 0
        if (haveHeader) {
            extraCount++
        } else if (haveFooter) {
            extraCount++
        }
        return getRealCount() + extraCount
    }

    override fun getItemViewType(position: Int): Int {
        return if (position == 0 && haveHeader) {
            TYPE_HEADER
        } else if (haveFooter && (position == getRealCount() && !haveHeader) || (position == getRealCount() + 1 && haveHeader)) {
            TYPE_FOOTER
        } else {
            TYPE_NORMAL
        }
    }

    override fun getItemId(position: Int): Long = position.toLong()

    inner class DataBindingViewHolder(itemView: View, internal var viewType: Int) : RecyclerView.ViewHolder(itemView)

    interface OnBindingViewHolderListener {
        fun onHolderBinding(holder: RecyclerView.ViewHolder, position: Int)
    }

    companion object {
        const val TYPE_HEADER = 1
        const val TYPE_FOOTER = 2
        const val TYPE_NORMAL = 0
    }
}